home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / dev / gcc / gcc270_src.lha / gcc-2.7.0-amiga / config / clipper / clipper.c next >
C/C++ Source or Header  |  1995-06-15  |  11KB  |  475 lines

  1. /* Subroutines for insn-output.c for Clipper
  2.    Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
  3.  
  4.    Contributed by Holger Teutsch (holger@hotbso.rhein-main.de)
  5.  
  6. This file is part of GNU CC.
  7.  
  8. GNU CC is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2, or (at your option)
  11. any later version.
  12.  
  13. GNU CC is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with GNU CC; see the file COPYING.  If not, write to
  20. the Free Software Foundation, 59 Temple Place - Suite 330,
  21. Boston, MA 02111-1307, USA.  */
  22.  
  23. #include <stdio.h>
  24. #include "config.h"
  25. #include "rtl.h"
  26. #include "regs.h"
  27. #include "hard-reg-set.h"
  28. #include "real.h"
  29. #include "insn-config.h"
  30. #include "conditions.h"
  31. #include "insn-flags.h"
  32. #include "output.h"
  33. #include "insn-attr.h"
  34. #include "tree.h"
  35. #include "c-tree.h"
  36. #include "expr.h"
  37. #include "flags.h"
  38. #include "machmode.h"
  39.  
  40. extern char regs_ever_live[];
  41.  
  42. extern int frame_pointer_needed;
  43.  
  44. static int frame_size;
  45.  
  46. /*
  47.  * compute size of a clipper stack frame where 'lsize' is the required
  48.  * space for local variables.
  49.  */
  50.  
  51. int
  52. clipper_frame_size (lsize)
  53.      int lsize;
  54. {
  55.   int i,size;                /* total size of frame */
  56.   int save_size;
  57.   save_size = 0;            /* compute size for reg saves */
  58.  
  59.   for (i = 16; i < 32; i++)
  60.     if (regs_ever_live[i] && !call_used_regs[i])
  61.       save_size += 8;
  62.  
  63.   for (i = 0; i < 16; i++)
  64.     if (regs_ever_live[i] && !call_used_regs[i])
  65.       save_size += 4;
  66.  
  67.   size = lsize + save_size;
  68.  
  69.   size = (size + 7) & ~7;        /* align to 64 Bit */
  70.   return size;
  71. }
  72.  
  73. /*
  74.  * prologue and epilogue output
  75.  * function is entered with pc pushed, i.e. stack is 32 bit aligned
  76.  *
  77.  * current_function_args_size == 0 means that the current function's args
  78.  * are passed totally in registers i.e fp is not used as ap.
  79.  * If frame_size is also 0 the current function does not push anything and
  80.  * can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit
  81.  * can be omitted.
  82.  *
  83.  */
  84. void
  85. output_function_prologue (file, lsize)
  86.      FILE *file;
  87.      int lsize;                /* size for locals */
  88. {
  89.   int i, offset;
  90.   int size;
  91.  
  92.   frame_size = size = clipper_frame_size (lsize);
  93.  
  94.   if (frame_pointer_needed)
  95.     {
  96.       fputs ("\tpushw  fp,sp\n", file);
  97.       fputs ("\tmovw   sp,fp\n", file);
  98.     }
  99.   else if (size != 0 || current_function_args_size != 0)
  100.     {
  101.       size += 4;            /* keep stack aligned */
  102.       frame_size = size;        /* must push data or access args */
  103.     }
  104.  
  105.   if (size)
  106.     {
  107.       if (size < 16)
  108.     fprintf (file, "\tsubq   $%d,sp\n", size);
  109.       else
  110.     fprintf (file, "\tsubi   $%d,sp\n", size);
  111.  
  112.       /* register save slots are relative to sp, because we have small positive
  113.      displacements and this works whether we have a frame pointer or not */
  114.  
  115.       offset = 0;
  116.       for (i = 16; i < 32; i++)
  117.     if (regs_ever_live[i] && !call_used_regs[i])
  118.       {
  119.         if (offset == 0)
  120.           fprintf (file, "\tstord  f%d,(sp)\n", i-16);
  121.         else
  122.           fprintf (file, "\tstord  f%d,%d(sp)\n", i-16, offset);
  123.         offset += 8;
  124.       }
  125.  
  126.       for (i = 0; i < 16; i++)
  127.     if (regs_ever_live[i] && !call_used_regs[i])
  128.       {
  129.         if (offset == 0)
  130.           fprintf (file, "\tstorw  r%d,(sp)\n", i);
  131.         else
  132.           fprintf (file, "\tstorw  r%d,%d(sp)\n", i, offset);
  133.         offset += 4;
  134.       }
  135.     }
  136. }
  137.  
  138. void
  139. output_function_epilogue (file, size)
  140.      FILE *file;
  141.      int size;                /* ignored */
  142. {
  143.   int i, offset;
  144.  
  145.   if (frame_pointer_needed)
  146.     {
  147.       offset = -frame_size;
  148.  
  149.       for (i = 16; i < 32; i++)
  150.     if (regs_ever_live[i] && !call_used_regs[i])
  151.       {
  152.         fprintf (file, "\tloadd  %d(fp),f%d\n", offset, i-16);
  153.         offset += 8;
  154.       }
  155.  
  156.       for (i = 0; i < 16; i++)
  157.     if (regs_ever_live[i] && !call_used_regs[i])
  158.       {
  159.         fprintf (file, "\tloadw  %d(fp),r%d\n", offset, i);
  160.         offset += 4;
  161.       }
  162.  
  163.       fputs ("\tmovw   fp,sp\n\tpopw   sp,fp\n\tret    sp\n",
  164.          file);
  165.     }
  166.  
  167.   else                    /* no frame pointer */
  168.     {
  169.       offset = 0;
  170.  
  171.       for (i = 16; i < 32; i++)
  172.     if (regs_ever_live[i] && !call_used_regs[i])
  173.       {
  174.         if (offset == 0)
  175.           fprintf (file, "\tloadd  (sp),f%d\n", i-16);
  176.         else
  177.           fprintf (file, "\tloadd  %d(sp),f%d\n", offset, i-16);
  178.         offset += 8;
  179.       }
  180.  
  181.       for (i = 0; i < 16; i++)
  182.     if (regs_ever_live[i] && !call_used_regs[i])
  183.       {
  184.         if (offset == 0)
  185.           fprintf (file, "\tloadw  (sp),r%d\n", i);
  186.         else
  187.           fprintf (file, "\tloadw  %d(sp),r%d\n", offset, i);
  188.         offset += 4;
  189.       }
  190.  
  191.       if (frame_size > 0)
  192.     {
  193.       if (frame_size < 16)
  194.         fprintf (file, "\taddq   $%d,sp\n", frame_size);
  195.       else
  196.         fprintf (file, "\taddi   $%d,sp\n", frame_size);
  197.     }
  198.  
  199.       fputs ("\tret    sp\n", file);
  200.     }
  201. }
  202.  
  203. /*
  204.  * blockmove
  205.  *
  206.  * clipper_movstr ()
  207.  */
  208. void
  209. clipper_movstr (operands)
  210.      rtx *operands;
  211. {
  212.   rtx dst,src,cnt,tmp,top,bottom,xops[3];
  213.   int align;
  214.   int fixed;
  215.  
  216.   extern FILE *asm_out_file;
  217.  
  218.   dst = operands[0];
  219.   src = operands[1];
  220.   /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */
  221.   align = INTVAL (operands[3]);
  222.   tmp = operands[4];
  223.   cnt = operands[5];
  224.  
  225.   if (GET_CODE (operands[2]) == CONST_INT) /* fixed size move */
  226.     {
  227.       if ((fixed = INTVAL (operands[2])) <= 0)
  228.     abort ();
  229.  
  230.       if (fixed <16)
  231.     output_asm_insn ("loadq  %2,%5", operands);
  232.       else
  233.     output_asm_insn ("loadi  %2,%5", operands);
  234.     }
  235.   else
  236.     {
  237.       fixed = 0;
  238.       bottom = (rtx)gen_label_rtx ();    /* need a bottom label */
  239.       xops[0] = cnt; xops[1] = bottom;
  240.       output_asm_insn ("movw   %2,%5", operands); /* count is scratch reg 5 */
  241.       output_asm_insn ("brle   %l1", xops);
  242.     }
  243.  
  244.  
  245.   top = (rtx)gen_label_rtx ();        /* top of loop label */
  246.   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (top));
  247.  
  248.  
  249.   xops[0] = src; xops[1] = tmp; xops[2] = dst;
  250.  
  251.   if (fixed && (align & 0x3) == 0)    /* word aligned move with known size */
  252.     {
  253.       if (fixed >= 4)
  254.     {
  255.       rtx xops1[2];
  256.       output_asm_insn(
  257.         "loadw  %a0,%1\n\taddq   $4,%0\n\tstorw  %1,%a2\n\taddq   $4,%2",
  258.               xops);
  259.  
  260.       xops1[0] = cnt; xops1[1] = top;
  261.       output_asm_insn ("subq   $4,%0\n\tbrgt   %l1", xops1);
  262.     }
  263.  
  264.       if (fixed & 0x2)
  265.     {
  266.       output_asm_insn ("loadh  %a0,%1\n\tstorh  %1,%a2", xops);
  267.       if (fixed & 0x1)
  268.         output_asm_insn ("loadb  2%a0,%1\n\tstorb  %1,2%a2", xops);
  269.     }
  270.       else
  271.     if (fixed & 0x1)
  272.       output_asm_insn ("loadb  %a0,%1\n\tstorb  %1,%a2", xops);
  273.     }
  274.   else
  275.     {
  276.       output_asm_insn(
  277.       "loadb  %a0,%1\n\taddq   $1,%0\n\tstorb  %1,%a2\n\taddq   $1,%2",
  278.               xops);
  279.  
  280.       xops[0] = cnt; xops[1] = top;
  281.       output_asm_insn ("subq   $1,%0\n\tbrgt   %l1", xops);
  282.     }
  283.  
  284.   if (fixed == 0)
  285.     ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (bottom));
  286. }
  287.  
  288.  
  289. print_operand_address (file, addr)
  290.      FILE *file;
  291.      register rtx addr;
  292. {
  293.   rtx op0,op1;
  294.  
  295.  retry:
  296.   switch (GET_CODE (addr))
  297.     {
  298.     case REG:
  299.       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
  300.       break;
  301.  
  302.     case PLUS:
  303.       /* can be 'symbol + reg' or 'reg + reg' */
  304.  
  305.       op0 = XEXP (addr, 0);
  306.       op1 = XEXP (addr, 1);
  307.  
  308.       if (GET_CODE (op0) == REG && GET_CODE (op1) == REG)
  309.     {
  310.       fprintf (file, "[%s](%s)",
  311.            reg_names[REGNO (op0)], reg_names[REGNO (op1)]);
  312.       break;
  313.     }
  314.  
  315.       if (GET_CODE (op0) == REG && CONSTANT_ADDRESS_P (op1))
  316.     {
  317.       output_addr_const (file, op1);
  318.       fprintf (file, "(%s)", reg_names[REGNO (op0)]);
  319.       break;
  320.     }
  321.  
  322.       if (GET_CODE (op1) == REG && CONSTANT_ADDRESS_P (op0))
  323.     {
  324.       output_addr_const (file, op0);
  325.       fprintf (file, "(%s)", reg_names[REGNO (op1)]);
  326.       break;
  327.     }
  328.       abort ();                /* Oh no */
  329.  
  330.     default:
  331.       output_addr_const (file, addr);
  332.     }
  333. }
  334.  
  335.  
  336. char *
  337. rev_cond_name (op)
  338.      rtx op;
  339. {
  340.   switch (GET_CODE (op))
  341.     {
  342.     case EQ:
  343.       return "ne";
  344.     case NE:
  345.       return "eq";
  346.     case LT:
  347.       return "ge";
  348.     case LE:
  349.       return "gt";
  350.     case GT:
  351.       return "le";
  352.     case GE:
  353.       return "lt";
  354.     case LTU:
  355.       return "geu";
  356.     case LEU:
  357.       return "gtu";
  358.     case GTU:
  359.       return "leu";
  360.     case GEU:
  361.       return "ltu";
  362.  
  363.     default:
  364.       abort ();
  365.     }
  366. }
  367.  
  368.  
  369. /* Do what is necessary for `va_start'.  The argument is ignored;
  370.    We fill in an initial va_list.  A pointer to this constructor
  371.    is returned. */
  372.  
  373.  
  374. struct rtx_def *
  375. clipper_builtin_saveregs (arglist)
  376.      tree arglist;
  377. {
  378.   extern int current_function_varargs;
  379.   rtx block, addr, argsize, scratch, r0_addr,r1_addr,f0_addr,f1_addr;
  380.  
  381.   /* Allocate the va_list constructor + save area for r0,r1,f0,f1 */
  382.  
  383.   block = assign_stack_local (BLKmode,
  384.                   (6 + 6) * UNITS_PER_WORD, 2 * BITS_PER_WORD);
  385.  
  386.   RTX_UNCHANGING_P (block) = 1;
  387.   RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
  388.  
  389.   addr = copy_to_reg (XEXP (block, 0));
  390.  
  391.   f0_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 24));
  392.   f1_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 32));
  393.   r0_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 40));
  394.   r1_addr =  gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 44));
  395.  
  396.  
  397.   /* Store float regs  */
  398.  
  399.   emit_move_insn (gen_rtx (MEM, DFmode, f0_addr), gen_rtx (REG, DFmode, 16));
  400.   emit_move_insn (gen_rtx (MEM, DFmode, f1_addr), gen_rtx (REG, DFmode, 17));
  401.  
  402.   /* Store int regs  */
  403.  
  404.   emit_move_insn (gen_rtx (MEM, SImode, r0_addr), gen_rtx (REG, SImode, 0));
  405.   emit_move_insn (gen_rtx (MEM, SImode, r1_addr), gen_rtx (REG, SImode, 1));
  406.  
  407.   /* Store the arg pointer in the __va_stk member.  */
  408.  
  409.   emit_move_insn (gen_rtx (MEM, SImode, addr),
  410.           copy_to_reg (virtual_incoming_args_rtx));
  411.           
  412.  
  413.   /* now move addresses of the saved regs into the pointer array */
  414.  
  415.   scratch = gen_reg_rtx (Pmode);
  416.  
  417.   emit_move_insn (scratch, r0_addr);
  418.   emit_move_insn (gen_rtx (MEM, SImode,
  419.                gen_rtx (PLUS, Pmode, addr,
  420.                     gen_rtx (CONST_INT, Pmode, 4))),
  421.           scratch);
  422.           
  423.   emit_move_insn (scratch, f0_addr);
  424.   emit_move_insn (gen_rtx (MEM, SImode,
  425.                gen_rtx (PLUS, Pmode, addr,
  426.                     gen_rtx (CONST_INT, Pmode, 8))),
  427.           scratch);
  428.           
  429.   emit_move_insn (scratch, r1_addr);
  430.   emit_move_insn (gen_rtx (MEM, SImode,
  431.                gen_rtx (PLUS, Pmode, addr,
  432.                     gen_rtx (CONST_INT, Pmode, 12))),
  433.           scratch);
  434.           
  435.   emit_move_insn (scratch, f1_addr);
  436.   emit_move_insn (gen_rtx (MEM, SImode,
  437.                gen_rtx (PLUS, Pmode, addr,
  438.                     gen_rtx (CONST_INT, Pmode, 16))),
  439.           scratch);
  440.  
  441.   /* Return the address of the va_list constructor, but don't put it in a
  442.      register.  This fails when not optimizing and produces worse code when
  443.      optimizing.  */
  444.  
  445.   return XEXP (block, 0);
  446. }
  447.  
  448.  
  449. /* Return truth value of whether OP can be used as an word register
  450.    operand. Reject (SUBREG:SI (REG:SF )) */
  451.  
  452. int
  453. int_reg_operand (op, mode)
  454.      rtx op;
  455.      enum machine_mode mode;
  456. {
  457.   return (register_operand (op, mode) &&
  458.       (GET_CODE (op) != SUBREG ||
  459.        GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT));
  460. }
  461.  
  462. /* Return truth value of whether OP can be used as a float register
  463.    operand. Reject (SUBREG:SF (REG:SI )) )) */
  464.  
  465. int
  466. fp_reg_operand (op, mode)
  467.      rtx op;
  468.      enum machine_mode mode;
  469. {
  470.   return (register_operand (op, mode) &&
  471.       (GET_CODE (op) != SUBREG ||
  472.        GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_FLOAT));
  473. }
  474.  
  475.